<?php

class institution {

	// Selecting users belonging to an institution
	const MEMBERSHIP_ALL = 1;
	const MEMBERSHIP_ADMIN = 2;

	// Deleting institutions
	const ORPHANS_RELINQUISH = 1;
	const ORPHANS_DELETE = 2;

	// Removing groups
	const GROUP_RELINQUISH = -100;

	public function create(user &$userObj, $name, $description, $baseGroup, $visibility){
		if($userObj->getAccessLevel() > -1){
			// User is able to create an institution
			
			$dbCon = db::singleton();
			
			$dbCon->startTransaction();
			
			try{
				// Create the institution
				$sql = "INSERT INTO " . SYS_DB_DBNAME . ".institution (name, description, private) VALUES('" . $dbCon->real_escape_string($name) . "', '" . $dbCon->real_escape_string($description) . "', '" . $dbCon->real_escape_string($visibility) . "')";
				$dbCon->single($sql);
				
				// Get the ID of the new institution
				$instID = $dbCon->insert_id;
				
				// Add the current user as an admin
				$sql = "INSERT INTO " . SYS_DB_DBNAME . ".institution_user (user_uID, institution_instID, admin, active) VALUES(" . (int)$userObj->getuID() . ", $instID, 1, 1)";
				
				$dbCon->single($sql);
				
				// Add the basegroup
				$userhasAccess = false;
				foreach($userObj->getManagedGroups() as $managedGroups){
					if($managedGroups[0] == $baseGroup) $userhasAccess = true;
				}
				
				if($userhasAccess){
					$sql = "UPDATE " . SYS_DB_DBNAME . ".group SET institution_instID=" . $instID . " WHERE gID=" . $dbCon->real_escape_string($baseGroup);
					$dbCon->single($sql);
				}
				
				$dbCon->commit();
				
				return $instID;
			} catch (Exception $e){
				$dbCon->rollback();
				return false;
			}
		} else {
			throw new PicBoardException("Invalid access permissions");
		}
	}
	
	public function remove(user &$userObj, $instID, $orphanedGroups = institution::ORPHANS_RELINQUISH){
		// Remove the institution
		
		if($instID == "" || (int)$instID == 1 || is_integer($instID) == false) throw new PicBoardException("Institution ID does not match");
		
		$dbCon = db::singleton();
		
		$dbCon->startTransaction();
		
		try {
		
			// Remove the user->institution links.
			$sql = "DELETE FROM " . SYS_DB_DBNAME . ".institution_user WHERE institution_instID=" . $dbCon->real_escape_string((int)$instID) . ";";
			
			$dbCon->single($sql);
			
			switch($orphanedGroups){
			
				case 1:
					$changeGroups = "UPDATE " . SYS_DB_DBNAME . ".group SET institution_instID=1 WHERE institution_instID=" . $dbCon->real_escape_string((int)$instID);
			
					$dbCon->single($changeGroups);
				
				break;
				
				case 2:
					// Get a list of the groups that are associated with the institution
					$gIDList = $dbCon->single( "SELECT gID FROM " . SYS_DB_DBNAME . ".group WHERE institution_instID=" . $dbCon->real_escape_string((int)$instID) );
										
					foreach($gIDList as $group){
						group::deleteGroup($userObj, $group['gID']);
					}
				break;
				
			
			}
			
			// Remove the institution itself.
			$sql = "DELETE FROM " . SYS_DB_DBNAME . ".institution WHERE instID=" . $dbCon->real_escape_string((int)$instID);
			
			$dbCon->commit();
			return true;
			
		} catch (Exception $e){
			$dbCon->rollback();
			return false;
		}
	}
	
	public function update(user &$userObj, $instID, array $newDetails){
		$instID = (int)$instID;
		// Update institution based on newDetails.
		// Does the user have access to update this institution?
		if(institution::isInInstitution($userObj, $instID, institution::MEMBERSHIP_ADMIN)){
			if(isset($newDetails['name'], $newDetails['description'])){
				$dbCon = db::singleton();
				
				$sql = "UPDATE " . SYS_DB_DBNAME . ".institution SET name='" . $dbCon->real_escape_string($newDetails['name']) . "', description ='" . $dbCon->real_escape_string($newDetails['description']) . "' WHERE instID=" . $dbCon->real_escape_string($instID);
				
				$result = $dbCon->single($sql);
				return true;
			} else {
				return false;
			}
		} else {
			return false;
		}

	}
	
	public static function getUserInstitutions(user &$userObj, $filter = institution::MEMBERSHIP_ALL){
		// Get a list of the institutions that the user is subsscribed to, filtered on $filter.
		switch($type){
			
			case 1:
				$sql = "SELECT COUNT(*) AS isInGroup FROM " . SYS_DB_DBNAME . "." . SYS_DB_PREFIX . "institution_user WHERE user_uID=" . $this->uID;
			break;
			
			case 2:
				$sql = "SELECT COUNT(*) AS isInGroup FROM " . SYS_DB_DBNAME . "." . SYS_DB_PREFIX . "institution_user WHERE user_uID=" . $this->uID . " AND admin=1";
			break;
		}
		
		$result = $dbCon->oneRow($sql);	
		return (BOOL)$result['isInGroup'];
	}
	
	public static function isInInstitution(user &$userObj, $instID, $filter = institution::MEMBERSHIP_ALL){
		// Get a list of the institutions that the user is subsscribed to, filtered on $filter.

		$dbCon = db::singleton();

		switch($filter){
			
			case 1:
				$sql = "SELECT COUNT(*) AS isInGroup FROM " . SYS_DB_DBNAME . "." . SYS_DB_PREFIX . "institution_user WHERE institution_instID=" . $dbCon->real_escape_string((int)$instID) . " AND user_uID=" . $userObj->getuID();
			break;
			
			case 2:
				$sql = "SELECT COUNT(*) AS isInGroup FROM " . SYS_DB_DBNAME . "." . SYS_DB_PREFIX . "institution_user WHERE institution_instID=" . $dbCon->real_escape_string((int)$instID) . " AND user_uID=" . $userObj->getuID() . " AND admin=1";
			break;
		}
		
		$result = $dbCon->oneRow($sql);	
		return (BOOL)$result['isInGroup'];
	}
	
	public static function getInstitutionGroups(user &$userObj, $instID){
		if(is_integer($instID) == false) throw new PicBoardException("Institution ID must be an integer.");
		$dbCon = db::singleton();
		
		$sql = "SELECT * FROM " . SYS_DB_DBNAME . ".group WHERE institution_instID=" . $dbCon->real_escape_string($instID);
		
		$results = $dbCon->single($sql);
		
		return $results;
	}
	
	public static function addUsers(user &$userObj, $id, array $userList){
		// Check to see if the user has access to this institution
		$hasAccess = false;
		foreach($userObj->rtnInstitution() as $k => $inst){
			if($inst['instID'] == $id && $inst['admin'] == 1) {
				$hasAccess = true;
				$institutionName = $inst['name'];	
			}
		}
	
		// Does the user have access to perform this function?
		if($hasAccess){
			$dbCon = db::singleton();
			
			$dbCon->startTransaction();
			
			// We need to perform these steps:
			// 1. For all users that are already in the system, give them access.
			// 2. For all users that are not, we need to send out an activation email. This will allow auto-enrollment into the institution
			
			$userList = array();
			foreach($_POST['data'] as $users) {
				$userList[$users['email']] = array("isAdmin" => $users['admin']);
			}
			
			// Create arrays for users that are going to be added, and users that are going to be emailed
			$inviteUsers 	= array();
			$addUsers 		= array();
			
			foreach( users::usernameListExists( array_keys($userList) ) as $k=> $user ){ 
				$addUsers[$user['emailAddress']] = array('id' => $user['uID']);
			}
			// Check diff for users that need to be invited
			$inviteUsers = array_diff(array_keys($userList), array_keys($addUsers));
			
			// Setup complete. Start processing the data we have gathered.
			
			
			try {
			
				// Start processing the users to add.
				if(count($addUsers) > 0){
					$sqlTemplate = "INSERT INTO " . SYS_DB_DBNAME . ".institution_user (user_uID, institution_instID, admin, active ) VALUES";
					foreach($addUsers as $key=> $user){
						$isAdmin = ($userList[$key]['isAdmin'] == "yes") ? 1 : 0;
						$sqlTemplate .= "(" . $dbCon->real_escape_string($user['id']) . "," . $dbCon->real_escape_string($id) . "," . $isAdmin . ",1),";
					}
					
					$insertSQL = trim($sqlTemplate, ",");
					
					$dbCon->single( $insertSQL );
				}
				
	
				if(count($inviteUsers) > 0){
				
					// First, we need to get a list of the users currently with invitations.			
				
					$users_awaiting = $dbCon->single("SELECT email FROM " . SYS_DB_DBNAME . ".invitations");
					$users_awaiting = util::flatten( $users_awaiting );
					
				
					$invite = new invite(new template('email.invite'));
					$sqlTemplate = "INSERT INTO " . SYS_DB_DBNAME . ".invitations (email, actHash, institution_instID, state) VALUES";
									
					// Start processing the users to invite.
					foreach($inviteUsers as $user){
						// If they are already pending, ignore.
						if( in_array($user, $users_awaiting) ) continue;
						
						// Is this user an admin?
						$isAdmin = ($userList[$user]['isAdmin'] == "yes") ? 1 : 0;
					
						$sqlTemplate .= "('" . $dbCon->real_escape_string($user) . "','" . $invite->hash($user, 'instActivation') . "'," . $dbCon->real_escape_string($id) . ",'" . $isAdmin . "'),";
					
						$message = $invite->generateMessage($userObj, $user, $institutionName, 'instActivation');
						
						mailHandler::sendMessage($user, "PicBoard Invitation", $message);
					}
					
					$insertSQL = trim($sqlTemplate, ",");
					
					$dbCon->single( $insertSQL );
				
				}
				
				$dbCon->commit();
				return true;
				
			} catch(Exception $e){
				$dbCon->rollback();
				return false;			
			}
						
			
		} else {
			return false;
		}
	}

	public static function numberofGroups(user &$userObj, $instID){
		if(is_integer($instID) == false) throw new PicBoardException("Argument 2 must be an integer.");
		
		if(institution::isInInstitution($userObj, $instID, institution::MEMBERSHIP_ADMIN) == false) throw new PicBoardException("You do not have adequate permissions to perform this function.");
		
		$dbCon = db::singleton();
		
		$sql = "SELECT COUNT(*) AS groupCount FROM " . SYS_DB_DBNAME . ".group WHERE institution_instID=" . $dbCon->real_escape_string($instID);
		
		$res = $dbCon->oneRow($sql);
		
		return (int)$res['groupCount'];
	}

	public static function addGroup(user &$userObj, $instID, $gID){
		if(is_integer($instID) == false || is_integer($gID) == false) throw new PicBoardException("Argument 2, 3, and 4 must be integers.");

		// Does the user have admin privilages to the group we're referencing, here?
		if($userObj->isInGroup($gID, user::GROUP_ADMINONLY) == false) throw new PicBoardException("This user does not have admin permissions to this group.");

		$dbCon = db::singleton();
		
		$dbCon->startTransaction();

		try {

			$sql = "UPDATE " . SYS_DB_DBNAME . ".group SET institution_instID=" . $dbCon->real_escape_string((int)$instID) . " WHERE gID=" . $dbCon->real_escape_string((int)$gID);
	
			$dbCon->single($sql);
			
			$dbCon->commit();
			
			return true;
		
		} catch (Exception $e){
			$dbCon->rollback();
			return false;
		}
		
		
	
	}
	
	public static function removeGroup(user &$userObj, $instID, $gID, $destination = institution::GROUP_RELINQUISH){
		// Destination is the designation for where to send the group. If GROUP_RELINQUISH is set, it'll be donated to the global namespace (1)
		
		if(is_integer($destination) == false || is_integer($instID) == false || is_integer($gID) == false) throw new PicBoardException("Argument 2, 3, and 4 must be integers.");
		
		// Does the user have admin privilages to the group we're referencing, here?
		if($userObj->isInGroup($gID, user::GROUP_ADMINONLY) == false) throw new PicBoardException("This user does not have admin permissions to this group.");
		
		// Does the institution have more than just this group?
		if(institution::numberofGroups($userObj, $instID) <= 1) throw new PicBoardException("You must have atleast one group in this institution.");
		
		$dbCon = db::singleton();
		
		$dbCon->startTransaction();
		
		try {
		
			switch($destination){
			
				// Relinquish to global namespace
				case institution::GROUP_RELINQUISH:
					$sql = "UPDATE " . SYS_DB_DBNAME . ".group SET institution_instID=1 WHERE gID=" . $dbCon->real_escape_string((int)$gID);
				break;
				
				default:
					$sql = "UPDATE " . SYS_DB_DBNAME . ".group SET institution_instID=" . $dbCon->real_escape_string((int)$destination) . " WHERE gID=" . $dbCon->real_escape_string((int)$gID);
				break;
			
			}
			
			$dbCon->single($sql);
			
			$dbCon->commit();
			
			return true;
		} catch (Exception $e){
			$dbCon->rollback();
			return false;
		}
	}

}

?>